use super::time::{UTime,SysTime,UClockData,SysConvertor,UDuration};
use core::slice::Iter;
use super::pair::{pair,mean,sub_f64,sdv2,Asf64};

pub fn error(r:&[pair<UTime,SysTime>],reference: &UClockData) -> (f64,f64) {
    let mut err = vec![];
    r.iter()
        .for_each(|pair(a,b)| err.push(b.diff(&reference.to_sys(&a)).asf64()));
    let me = mean(&err);
    let mut se = vec![];
    sub_f64(&err,me,&mut se);
    (me,sdv2(&se,&se))
}

pub fn werror(r:&[pair<UTime,SysTime>],reference: &UClockData) -> (f64,f64) {
    let mut err = vec![];
    for i in 0..r.len() {
        let pair(a,b) = r[i];
        err.push(b.diff(&reference.to_sys(&a)).asf64()*(i as f64));
    }
    let me = mean(&err);
    let mut se = vec![];
    sub_f64(&err,me,&mut se);
    (2f64*me/((r.len()-1) as f64),sdv2(&se,&se))
}

fn ls(x:&Vec<f64>,y:&Vec<f64>) -> UClockData {
    let mx = mean(x);
    let my = mean(y);
    let mut sx = vec![];
    sub_f64(x,mx,&mut sx);
    let mut sy = vec![];
    sub_f64(y,my,&mut sy);
    let sxx = sdv2(&sx,&sx);
    let syx = sdv2(&sy,&sx);
    let cpu_start = SysTime((mx+0.5f64) as i64);
    let self_start = UTime((my+0.5f64) as i64);
    UClockData { 
            rate_nano:syx/sxx, 
            self_start:self_start,
            cpu_start: cpu_start,
            quality: 1.0f64,
    }
}
fn error_f64(d:&UClockData,x: &Vec<f64>, y: &Vec<f64>) -> Vec<f64> { 
    let mut e = vec![];
    for i in 0..x.len() {
        e.push((y[i]-d.self_start.asf64())-(x[i]-d.cpu_start.asf64())*d.rate_nano);
    }
    e
}
pub fn least_square<T:Asf64,E:Asf64>(r:&[pair<T,E>]) -> UClockData {
    let mut x = vec![];
    let mut y = vec![];
    r.iter()
        .for_each(|pair(a,b)| {x.push(b.asf64()); y.push(a.asf64());});
    let d = ls(&x, &y);
    let e = error_f64(&d,&x,&y);
    let ee = sdv2(&e,&e).sqrt();
    let mut xx = vec![];
    let mut yy = vec![];
    for i in 0..e.len() {
        if e[i].abs() < 3f64*ee {
            xx.push(x[i]);
            yy.push(y[i]);
        } 
    }
    println!("data len:{}",xx.len());
    ls(&xx,&yy)
}
pub fn wleast_square<T:Asf64,E:Asf64>(r:&[pair<T,E>],p:usize,o:pair<UTime,SysTime>) -> UClockData {
    let mut x = vec![];
    let mut y = vec![];
    r.iter()
        .for_each(|pair(a,b)| {x.push(b.asf64()); y.push(a.asf64());});
    let d = ls(&x, &y);
    let e = error_f64(&d,&x,&y);
    let ee = sdv2(&e,&e).sqrt();
    let mut xx = vec![];
    let mut yy = vec![];
    let mut c = e.len() as f64;
    for i in p..e.len() {
        if e[i].abs() < 3f64*ee {
            xx.push((x[i] - o.1.asf64())/c);
            yy.push((y[i] - o.0.asf64())/c);
        } 
        c -= 1f64;
    }
    for i in 0..p {
        if e[i].abs() < 3f64*ee {
            xx.push((x[i] - o.1.asf64())/c);
            yy.push((y[i] - o.0.asf64())/c);
        } 
        c -= 1f64;
    }
    println!("data len:{}",xx.len());
    wls(&xx,&yy,o)
}

fn wls(x:&Vec<f64>,y:&Vec<f64>,o:pair<UTime,SysTime>) -> UClockData {
    let mx = mean(x);
    let my = mean(y);
    let mut sx = vec![];
    sub_f64(x,mx,&mut sx);
    let mut sy = vec![];
    sub_f64(y,my,&mut sy);
    let sxx = sdv2(&sx,&sx);
    let syx = sdv2(&sy,&sx);
    let cpu_start = SysTime((mx+0.5f64+o.1.asf64()) as i64);
    let self_start = UTime((my+0.5f64+o.0.asf64()) as i64);
    UClockData { 
            rate_nano:syx/sxx, 
            self_start:self_start,
            cpu_start: cpu_start,
            quality: 1.0f64,
    }
}